home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / insertarc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-07  |  11.0 KB  |  442 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1986, 1988 Regents of the University of California
  5.    Copyright (c) 1989, Tera Computer Company
  6.  **/
  7.  
  8.   /**
  9.      Routines to insert an arc.  This can be tricky, since certain arcs
  10.      are illegal.  Also, if there's already an arc between two nodes, a new
  11.      one must follow the same path as the old ones
  12.    **/
  13.  
  14. #include "malloc.h"
  15. #include "attribute.h"
  16. #include "digraph.h"
  17. #include "screen.h"
  18. #include "globals.h"
  19. #include "scrdep.h"
  20. #include "interf.h"
  21. #include "tedge.h"
  22. #include "clip.h"
  23.  
  24. NODE *CreateDummy(), *get_next_node(), *next_dummy();
  25. NODE *get_prev_node();
  26. BOOL DoInsArcEnd();
  27. char *UniqueName();
  28. BOOL on_screen();
  29. OUTEDGE *get_edge();
  30. INEDGE *get_in_edge();
  31.  
  32. static NODE *start, *end, *firstnode;
  33. static NODE **addedN = NULL;    /* keep track of what dummy nodes were added */
  34. static int num_added;
  35.  
  36. BOOL DoSetUpInsArc()
  37.   /* return FALSE if you can't add an arc from here */
  38. {
  39.     start = (NODE *) ICurNode();
  40.  
  41.     if (Coalescer(start))
  42.       /**
  43.      Disallow edges from coalescer nodes
  44.        **/
  45.     {
  46.     IChangeStatusLine("Cannot add edge from coalescer node", FALSE);
  47.     return FALSE;
  48.     }
  49.     else
  50.     {
  51.         firstnode = start;
  52.         num_added = 0;
  53.     
  54.         if (addedN != NULL)
  55.         {
  56.         dispose(addedN);
  57.         addedN = NULL;
  58.         }
  59.     
  60.         IChangeStatusLine("Inserting arc ...", TRUE);
  61.     return TRUE;
  62.     }
  63. }
  64.  
  65. BOOL DoInsArcEnd()
  66. {
  67.     int ax, ay, curx, cury;
  68.  
  69.     if (start == NULL)
  70.       /* this better not happen */
  71.     {
  72.     return TRUE;
  73.     }
  74.  
  75.     IGetCurPos(&curx, &cury);
  76.     ax = SCRX_TO_ABSX(&screen, curx);
  77.     ay = SCRY_TO_ABSY(&screen, cury);
  78.  
  79.       /**
  80.          check if on node.  if yes, put new edge in edgelist.  if not,
  81.          set down dummy node and make it the new start node.
  82.        **/
  83.     if ((end = (NODE *) ICurNode()) == NULL)     
  84.       /* dropping on a vacant spot */
  85.     {
  86.         end = CreateDummy(digraph, ax, ay);
  87.     ScrAddDummy (end, 1, &screen, TRUE);
  88.     (void) CreateEdge(digraph, start, end);
  89.         ScrAddEdge(digraph, start, end, &screen, TRUE);
  90.  
  91.       /* keep a record of what was added */
  92.     num_added++;
  93.  
  94.     if (addedN == NULL)
  95.     {
  96.         addedN = (NODE **) malloc(sizeof(NODE *));
  97.     }
  98.     else
  99.     {
  100.         addedN = (NODE **) realloc((char *) addedN, 
  101.                        num_added * sizeof(NODE *));
  102.     }
  103.  
  104.     addedN[num_added - 1] = end;
  105.         start = end;
  106.     return FALSE;
  107.     }
  108.     else if (Is_dummy(end))     /* Trying to drop on a dummy */
  109.     {
  110.         IChangeStatusLine(
  111.         "Can't end arc on a dummy node.  Insertion aborted", FALSE);
  112.     DeleteAdded(firstnode, addedN, num_added);
  113.     return TRUE;
  114.     }
  115.     else if (Coalescer(end))    /* trying to drop on a coalescer */
  116.     {
  117.         IChangeStatusLine(
  118.         "Can't end arc on a coalescer node.  Insertion aborted", FALSE);
  119.     DeleteAdded(firstnode, addedN, num_added);
  120.     return TRUE;
  121.     }
  122.     else if (firstnode == end) 
  123.     {        
  124.              /* can't start and finish in the same place */
  125.          IChangeStatusLine(
  126.         "Can't draw an edge to the same node.  Insertion aborted",
  127.         FALSE);
  128.     DeleteAdded(firstnode, addedN, num_added);
  129.     return TRUE;
  130.     }
  131.     else
  132.     {
  133.           /* dropping on a node */
  134.  
  135.       /** 
  136.          if there are edges already between the beginning and ending node,
  137.          make this one follow their path 
  138.        **/
  139.     if (num_edges(firstnode, end) != 0)
  140.     {
  141.         DeleteAdded(firstnode, addedN, num_added);
  142.         new_follow_edge(firstnode, end, FALSE);
  143.     }
  144.     else if (num_edges(end, firstnode) != 0)
  145.     {
  146.         DeleteAdded(firstnode, addedN, num_added);
  147.         new_follow_edge(end, firstnode, TRUE);
  148.     }
  149.     else    /* this is new, so can leave it as is */
  150.     {
  151.         (void) CreateEdge(digraph, start, end);
  152.  
  153.         if (start != firstnode)
  154.           /* dummies were added between */
  155.         {
  156.             char **attr;
  157.             int i;
  158.     
  159.                 ScrAddEdge(digraph, start, end, &screen, TRUE);
  160.     
  161.                 /**
  162.                  create in_edge & out_edge between the 2 non-dummies.
  163.                  We don't want to fool around with the prev&succ set.
  164.                  Give it null edge attributes.  
  165.                **/
  166.     
  167.             attr = (char **) malloc (NEdgeAttr(digraph) * sizeof(char *));
  168.     
  169.             for (i = 0; i < NEdgeAttr(digraph); i++)
  170.             {
  171.             strsave(attr[i], NULL_STRING);
  172.             }
  173.     
  174.                 add_out_edge(firstnode, attr, DEFAULT_BRUSH, DEFAULT_COLOR, 
  175.                  Vno(end), 1);
  176.                 add_in_edge(end, Vno(firstnode), 1);
  177.         }
  178.         else
  179.         {
  180.                 draw_edge(digraph, get_edge(digraph, start, end, 1), 
  181.               start, end, 1, &screen, TRUE);
  182.         }
  183.     }
  184.  
  185.         start = NULL;
  186.     num_added = 0;
  187.         EndInsertArc();
  188.     return TRUE;
  189.     }
  190. }
  191.  
  192. EndInsertArc()
  193. {
  194.     IChangeStatusLine("End arc insertion", FALSE);
  195.     graphChanged = TRUE;
  196.     ckpt_done = FALSE;
  197. }
  198.  
  199. DeleteAdded(start, nodes, num_nodes)
  200. NODE *start, **nodes;
  201. int num_nodes;
  202.   /**
  203.      for whatever reason, we want to delete the chain of edges and dummy
  204.      nodes we've just added 
  205.    **/
  206. {
  207.     int i;
  208.     int ord = 1;
  209.  
  210.     if (num_nodes != 0)
  211.     {
  212.     IDelEdge((char *) start, (char *) nodes[0], ord);
  213.     remove_link(start, nodes[0]);
  214.  
  215.         for (i = 1; i < num_nodes; i++)
  216.         {
  217.         IDelEdge((char *) nodes[i-1], (char *) nodes[i], ord);
  218.         remove_link(nodes[i-1], nodes[i]);
  219.         IDelNode((char *) nodes[i-1], ord);
  220.         dispose_node(digraph, nodes[i-1]);
  221.     }
  222.  
  223.     IDelNode((char *) nodes[num_nodes-1], ord);
  224.     dispose_node(digraph, nodes[num_nodes-1]);
  225.     }
  226. }
  227.  
  228. new_follow_edge(fromnode, tonode, reversed)
  229. NODE *fromnode, *tonode;
  230. BOOL reversed;
  231.   /**
  232.      we know there's an edge from fromnode to tonode.  'Follow' it (go
  233.      to the same dummy nodes, if any, etc.)  Since an edge exists already,
  234.      there's no need to add any links, just add the in and out edges and
  235.      draw them on the screen 
  236.    **/
  237. {
  238.     char **attr;
  239.     int ord, i;
  240.     OUTEDGE *outedge;
  241.     INEDGE *inedge;
  242.     VNO to_vno;
  243.     NODE *nextnode, *prevnode;
  244.     
  245.     attr = (char **) malloc (NEdgeAttr(digraph) * sizeof(char *));
  246.     ord = max_edges(fromnode, tonode) + 1;
  247.    
  248.     for (i = 0; i < NEdgeAttr(digraph); i++)
  249.     {
  250.     strsave(attr[i], NULL_STRING);
  251.     }
  252.     
  253.     add_out_edge(fromnode, attr, DEFAULT_BRUSH, DEFAULT_COLOR,
  254.              Vno(tonode), ord);
  255.     add_in_edge(tonode, Vno(fromnode), ord);
  256.  
  257.     if (reversed)
  258.     {
  259.     outedge = get_edge(digraph, fromnode, tonode, ord);
  260.     inedge = get_in_edge(digraph, fromnode, tonode, ord);
  261.     Edge_reversed(outedge) = TRUE;
  262.         Edge_reversed(inedge) = TRUE;
  263.     }
  264.  
  265.     nextnode = NULL;
  266.  
  267.     each_element(Succ_set(fromnode), to_vno)
  268.     loop
  269.     /* look for a dummy node between fromnode and tonode */
  270.  
  271.     if (Is_dummy(Node(digraph, to_vno)) &&
  272.         get_next_node(digraph, Node(digraph, to_vno)) == tonode)
  273.     {
  274.         nextnode = Node(digraph, to_vno);
  275.             draw_edge(digraph, get_edge(digraph, fromnode, nextnode, ord), 
  276.               fromnode, nextnode, ord, &screen, TRUE);
  277.  
  278.           do
  279.         {
  280.         ScrAddDummy(nextnode, ord, &screen, TRUE);
  281.         prevnode = nextnode;
  282.         nextnode = next_dummy(digraph, nextnode);
  283.                 draw_edge(digraph, get_edge(digraph, prevnode, nextnode, ord), 
  284.               prevnode, nextnode, ord, &screen, TRUE);
  285.         } while (Is_dummy(nextnode));
  286.  
  287.         break;
  288.     }
  289.     endloop;
  290.  
  291.     if (nextnode == NULL)
  292.     {
  293.         draw_edge(digraph, get_edge(digraph, fromnode, tonode, ord), 
  294.           fromnode, tonode, ord, &screen, TRUE);
  295.     }
  296. }
  297.     
  298. NODE *CreateDummy(digraph, x_pos, y_pos)
  299. DIGRAPH *digraph;
  300. int x_pos, y_pos;
  301.   /* Create a dummy node at (x_pos, y_pos) */
  302. {
  303.     NODE *node, *CreateNode();
  304.     char name[MAXSTR];
  305.  
  306.     strcpy(name, UniqueName());
  307.  
  308.     node = CreateNode(digraph, name, NULL_STRING, x_pos, y_pos);
  309.     Status(node) = DUMMY;
  310.     Shape(node) = POINT;
  311.     Half_width(node) = DUMMY_HALF_WIDTH;
  312.     Half_height(node) = 0;
  313.     return (node);
  314. }
  315.  
  316. ScrAddEdge(digraph, fromnode, tonode, screen, draw)
  317. DIGRAPH *digraph;
  318. NODE *fromnode, *tonode;
  319. SCREEN *screen;
  320. BOOL draw;
  321.   /**
  322.      add an edge to the screen from fromnode to tonode.  No edges
  323.      exist between these two nodes.  Looks a lot like draw_edge, but
  324.      we can't use drawedge becase tonode could be a dummy node
  325.      without a successor (which would make draw_edge core dump)
  326.    **/
  327. {
  328.     double from_x;        /* x-coordinate of start of edge */
  329.     double from_y;            /* y-coordinates of start of edge */
  330.     double to_x;        /* x-coordinate of end of edge */
  331.     double to_y;        /* y-coordinates of end of edge */
  332.     NODE *prevnode;
  333.     TEDGE *edge;
  334.     BOOL parrow, reversed;
  335.     BRUSH brush;
  336.     COLOR color;
  337.  
  338.     parrow = FALSE;
  339.     reversed = FALSE;
  340.  
  341.     edge = (TEDGE *) malloc(sizeof(TEDGE));
  342.     strsave(edge->label, NULL_STRING);            /* no label yet */
  343.     edge->tonode = (char *) tonode;
  344.     edge->fromnode = (char *) fromnode;
  345.     edge->ord = 1;
  346.  
  347.       /* clip in both directions */
  348.     Clip(fromnode, tonode, edge->ord, &from_x, &from_y, &to_x, &to_y, screen);
  349.  
  350.     if (!Is_dummy(tonode)) 
  351.     {
  352.         if (outedge_reversed(digraph, fromnode, tonode, edge->ord)) 
  353.         {
  354.             parrow = TRUE;
  355.             reversed = TRUE;
  356.         } 
  357.         else
  358.     {
  359.         if (Is_dummy(fromnode)) 
  360.             {
  361.                 prevnode = get_prev_node(digraph, fromnode);
  362.             }
  363.             else 
  364.             {
  365.                 prevnode = fromnode;
  366.             }
  367.  
  368.             if (!outedge_reversed(digraph, prevnode, tonode, edge->ord)) 
  369.             {
  370.                 parrow = TRUE;
  371.         }
  372.         }
  373.     }
  374.  
  375.     brush = DEFAULT_BRUSH;
  376.     color = DEFAULT_COLOR;
  377.  
  378.     if (reversed)
  379.     {
  380.         IAddEdge(
  381.              (int) ABSX_TO_SCRX(screen, to_x), 
  382.              (int) ABSY_TO_SCRY(screen, to_y), 
  383.                 (int) ABSX_TO_SCRX(screen, from_x), 
  384.              (int) ABSY_TO_SCRY(screen, from_y), 
  385.              parrow, (char *) edge, edge->label, brush, color, draw, edge->ord);
  386.     }
  387.     else
  388.     {
  389.         IAddEdge(
  390.                 (int) ABSX_TO_SCRX(screen, from_x), 
  391.              (int) ABSY_TO_SCRY(screen, from_y), 
  392.              (int) ABSX_TO_SCRX(screen, to_x), 
  393.              (int) ABSY_TO_SCRY(screen, to_y), 
  394.              parrow, (char *) edge, edge->label, brush, color, draw, edge->ord);
  395.     }
  396. }
  397.  
  398. ScrAddDummy(node, ord, screen, draw)
  399. NODE *node;     /* node to draw */
  400. int ord;    /* ordinality of dummy node */
  401. SCREEN *screen;    /* window information */
  402. BOOL draw;  /* draw it now, or wait? */
  403.   /**
  404.      much like draw_node, except we assume a lot of values.  This should be a
  405.      newly added dummy node 
  406.    **/
  407. {
  408.     char *text;
  409.     char upbc[20];     /* up or down bc */
  410.     char downbc[20];     /* up or down bc */
  411.  
  412.     if (on_screen(node))
  413.     {
  414.     int shift;
  415.  
  416.         strsave(text, NULL_STRING);
  417.         strcpy(upbc, NULL_STRING);
  418.         strcpy(downbc, NULL_STRING);
  419.  
  420.     shift = ORD_TO_SHIFT(ord);
  421.     
  422.     if (markDummyNodes)
  423.     {
  424.         IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) + shift), 
  425.                   (int) ABSY_TO_SCRY(screen, Y_position(node)), 
  426.               1, 1, 
  427.                 RECTANGLE, text, Is_dummy(node), 
  428.               (char *) node, upbc, downbc, 
  429.               Brush(node), Color(node), draw, ord);
  430.     }
  431.     else
  432.     {
  433.         IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) + shift), 
  434.                       (int) ABSY_TO_SCRY(screen, Y_position(node)), 
  435.               0, 0, 
  436.                 POINT, text, Is_dummy(node), 
  437.               (char *) node, upbc, downbc, 
  438.               Brush(node), Color(node), draw, ord);
  439.     }
  440.     }
  441. } /* ScrAddDummy */
  442.